﻿namespace Yaaf.WP7.NativeAccess.ComWrapper.AllDevices.COM_NativeIO
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;

    using Yaaf.Wp7.AdvancedExplorer;
    using Yaaf.WP7.NativeAccess.Helper;

    internal class DataBuffer<T>
    {
        private T[] buffer;

        private int currentIndex;

        public DataBuffer(int size)
        {
            buffer = new T[size];
            currentIndex = 0;
        }

        public void AddValue(T value)
        {
            buffer[currentIndex] = value;
            var nextIndex = (currentIndex + 1) % buffer.Length;
            currentIndex = nextIndex;
        }

        public IEnumerable<T> Values
        {
            get
            {
                return buffer;
            }
        }
    }

    public class Directory
    {
        internal static DataBuffer<WIN32_FIND_DATA> buffer = new DataBuffer<WIN32_FIND_DATA>(5); 

        internal static IEnumerable<WIN32_FIND_DATA> EnumerateDirectory(string path, string searchString, bool fullName = false)
        {
            IntPtr hFind = IntPtr.Zero;
            WIN32_FIND_DATA findData;

            string fullPathQuery = System.IO.Path.Combine(path, searchString);

            int ret = NativeIODllInterop.FindFirstFile(fullPathQuery, out findData, out hFind);
            Logger.Instance.WriteLine(
                     "FindFirstFile (Path: {0}, FindData.Name: {1}, hFind-Handle: {2}, Return Value: {3})", path, findData.cFileName, hFind.ToString(), ret);
            
            if (ret == 0)
            {
                yield break;
            }

            if (hFind == NativeIODllInterop.INVALID_HANDLE_VALUE)
            {
                int err = Microsoft.Phone.InteropServices.Marshal.GetLastWin32Error();
                throw new IOException(string.Format("Error opening directory (LastWin32Error: {0}, Return Value: {1}, FindData.Name: {2})", err, ret, findData.cFileName));
            }

            do
            {
                var copy = findData;
                copy.cFileName = Path.Combine(path, findData.cFileName);
                buffer.AddValue(copy);
                if (fullName)
                {
                    yield return copy;
                }
                else
                {
                    yield return findData;
                }
                ret = NativeIODllInterop.FindNextFile(hFind, out findData);
                //Logger.Instance.WriteLine(
                //    "FindNextFile (FindData.Name: {0}, Return Value: {1})", findData.cFileName, ret);
                if (ret == 0)
                {
                    break;
                }
            } while (true);

            ret = NativeIODllInterop.FindClose(hFind);
            Logger.Instance.WriteLine("FindClose (Return Value: {0})", ret);
        }

        public static string[] GetFiles(string path, string searchString = "*")
        {
            return EnumerateDirectory(path, searchString)
                    .Where(f => (f.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory)
                    .Select(f => f.cFileName)
                    .ToArray();
            //var fileList = new List<string>();

            //IntPtr hFind = IntPtr.Zero;
            //WIN32_FIND_DATA findData;

            //string fullPathQuery = System.IO.Path.Combine(path, searchString);

            //int ret = NativeIODllInterop.FindFirstFile(fullPathQuery, out findData, out hFind);

            //if (ret == 0)
            //{
            //    return fileList.ToArray();
            //}

            //if (hFind == NativeIODllInterop.INVALID_HANDLE_VALUE)
            //{
            //    int err = Microsoft.Phone.InteropServices.Marshal.GetLastWin32Error();
            //    throw new InteropException("Error opening directory: " + err);
            //}

            //if ((findData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory)
            //{
            //    fileList.Add(findData.cFileName);
            //}

            //while (true)
            //{
            //    ret = NativeIODllInterop.FindNextFile(hFind, out findData);

            //    if (ret == 0)
            //    {
            //        break;
            //    }

            //    if ((findData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory)
            //    {
            //        fileList.Add(findData.cFileName);
            //    }
            //}

            //NativeIODllInterop.FindClose(hFind);
            //return fileList.ToArray();
        }

        public static string[] GetDirectories(string path, string searchString = "*")
        {
            return EnumerateDirectory(path, searchString)
                       .Where(f => (f.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory)
                       .Select(f => f.cFileName)
                       .ToArray();
            //var fileList = new List<string>();

            //IntPtr hFind = IntPtr.Zero;
            //WIN32_FIND_DATA findData;

            //string fullPathQuery = System.IO.Path.Combine(path, searchString);

            //int ret = NativeIODllInterop.FindFirstFile(fullPathQuery, out findData, out hFind);

            //if (ret == 0)
            //{
            //    return fileList.ToArray();
            //}

            //if (hFind == NativeIODllInterop.INVALID_HANDLE_VALUE)
            //{
            //    int err = Microsoft.Phone.InteropServices.Marshal.GetLastWin32Error();
            //    throw new InteropException("Error opening directory: " + err);
            //}

            //if ((findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory)
            //{
            //    fileList.Add(findData.cFileName);
            //}

            //while (true)
            //{
            //    ret = NativeIODllInterop.FindNextFile(hFind, out findData);

            //    if (ret == 0)
            //    {
            //        break;
            //    }

            //    if ((findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory)
            //    {
            //        fileList.Add(findData.cFileName);
            //    }
            //}

            //NativeIODllInterop.FindClose(hFind);
            //return fileList.ToArray();
        }

    }
}
